﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Pavilion.DesignerTool
{
    public class NodeCopyPasteMananger
    {
        private List<LinkWrapper> copiedLinkWrappers;
        private List<NodeBaseWrapper> copiedNodeWrappers;
        private Dictionary<string, NodeBaseWrapper> copiedNodesAssociations;

        public NodeCopyPasteMananger()
        {
            copiedLinkWrappers = new List<LinkWrapper>();
            copiedNodeWrappers = new List<NodeBaseWrapper>();
            copiedNodesAssociations = new Dictionary<string, NodeBaseWrapper>();
        }

        public void CopySelectedItems(object[] array)
        {
            copiedLinkWrappers.Clear();
            copiedNodeWrappers.Clear();

            IEnumerable<NodeBaseWrapper> copiedNodes = array
                .Where((item) => item is NodeBaseWrapper)
                .Select((item) => item as NodeBaseWrapper)
                .Where((item) => !(item.Node is EntryNode));

            copiedNodeWrappers.AddRange(CloneNodeBaseWrappers(copiedNodes));

            copiedLinkWrappers.AddRange(array
               .Where((item) => item is LinkWrapper)
               .Select((item) => item as LinkWrapper)
               .Where((linkWrapper) => copiedNodes.Contains(linkWrapper.Start) && copiedNodes.Contains(linkWrapper.End)));
        }

        public void Paste(NodeScriptViewModel viewModel)
        {
            IEnumerable<NodeBaseWrapper> clonedNodeWrappers = CloneNodeBaseWrappers(copiedNodeWrappers);

            foreach (NodeBaseWrapper copiedNodeWrapper in clonedNodeWrappers)
            {
                ValidateIfAnimationExistsWithinCurrentResource(copiedNodeWrapper.Node, viewModel);
                copiedNodeWrapper.Node.Name = viewModel.CurrentContainerNode.GetUniqueName(copiedNodeWrapper.Name);
                viewModel.AddNode(copiedNodeWrapper);
            }

            foreach (LinkWrapper linkWrapper in copiedLinkWrappers)
            {
                NodeBaseWrapper start = copiedNodesAssociations[(linkWrapper.Start as NodeBaseWrapper).Name];
                NodeBaseWrapper end = copiedNodesAssociations[(linkWrapper.End as NodeBaseWrapper).Name];
                List<ILock> clonedLockCollection = new List<ILock>(linkWrapper.Link.LockCollection.Select((item) => item.Clone()));

                viewModel.AddLink(start, end, clonedLockCollection, linkWrapper.OpenCriteria);
            }
        }

        private IEnumerable<NodeBaseWrapper> CloneNodeBaseWrappers(IEnumerable<NodeBaseWrapper> nodeBaseWrapperList)
        {
            List<NodeBaseWrapper> clonedNodeBaseWrapperList = new List<NodeBaseWrapper>();
            copiedNodesAssociations.Clear();

            foreach (NodeBaseWrapper originalNodeWrapper in nodeBaseWrapperList)
            {
                NodeBase nodeBase = originalNodeWrapper.Node.Clone();
                NodeBaseWrapper newNodeBaseWrapper = NodeBaseWrapper.CreateNodeBaseWrapper(nodeBase);

                if (originalNodeWrapper is ContainerNodeWrapper)
                    AllignPosition(originalNodeWrapper as ContainerNodeWrapper, newNodeBaseWrapper as ContainerNodeWrapper);

                clonedNodeBaseWrapperList.Add(newNodeBaseWrapper);
                copiedNodesAssociations.Add(newNodeBaseWrapper.Name, newNodeBaseWrapper);
            }

            return clonedNodeBaseWrapperList;
        }

        private void ValidateIfAnimationExistsWithinCurrentResource(NodeBase nodeBase, NodeScriptViewModel viewModel)
        {
            if (nodeBase is AnimationNode)
            {
                if (!viewModel.NodeScriptWrapper.ResourceData.ContainsAnimationData((nodeBase as AnimationNode).Animation))
                    (nodeBase as AnimationNode).Animation = null;
            }
            else if (nodeBase is ContainerNode)
            {
                foreach (NodeBase innerNode in (nodeBase as ContainerNode).NodeCollection)
                    ValidateIfAnimationExistsWithinCurrentResource(innerNode, viewModel);
            }
        }

        private void AllignPosition(ContainerNodeWrapper source, ContainerNodeWrapper targetToAllign)
        {
            for (int i = 0; i < source.ConnectableItems.Count; i++)
            {
                (targetToAllign.ConnectableItems[i] as NodeBaseWrapper).Position = (source.ConnectableItems[i] as NodeBaseWrapper).Position;

                if (targetToAllign.ConnectableItems[i] is ContainerNodeWrapper)
                    AllignPosition(targetToAllign.ConnectableItems[i] as ContainerNodeWrapper, source.ConnectableItems[i] as ContainerNodeWrapper);
            }
        }
    }
}
